[PATCH] detect/alert: check alert queue capacity before expanding
authorShivani Bhardwaj <shivani@oisf.net>
Mon, 5 Jan 2026 13:57:11 +0000 (19:27 +0530)
committerAndreas Dolp <dev@andreas-dolp.de>
Sun, 22 Feb 2026 12:28:52 +0000 (13:28 +0100)
So far, the alert queue was expanded by doubling in size w/o any
boundary checks in place. This led to situations where doubling
the alert_queue_capacity meant overflow of the very same value
stored in det_ctx.
This led to heap-use-after-free in some conditions where
det_ctx->alert_queue_capacity overflowed.

Fix this by capping the max of alert_queue_capacity by checking if its
expansion could result in an overflow.

Security 8190

(cherry picked from commit ac1eb394181530430fb7262969f423a1bf8f209b)

Origin: upstream, https://github.com/OISF/suricata/commit/5789a3d3760dbf33d93fc56c27bd9529e5bdc8f2.patch
Bug: https://redmine.openinfosecfoundation.org/issues/8190
Subject: Upstream fix for CVE-2026-22264

Gbp-Pq: Name CVE-2026-22264.patch

src/detect-engine-alert.c

index 466ca45703767319e0f1f6aa2c3566613556dcc1..978370815e7ee110e056e32e1e9dd3c24c896b9d 100644 (file)
@@ -238,6 +238,22 @@ void AlertQueueFree(DetectEngineThreadCtx *det_ctx)
     det_ctx->alert_queue_capacity = 0;
 }
 
+static inline uint16_t AlertQueueExpandDo(DetectEngineThreadCtx *det_ctx, uint16_t new_cap)
+{
+    DEBUG_VALIDATE_BUG_ON(det_ctx->alert_queue_capacity >= new_cap);
+
+    void *tmp_queue = SCRealloc(det_ctx->alert_queue, new_cap * sizeof(PacketAlert));
+    if (unlikely(tmp_queue == NULL)) {
+        /* queue capacity didn't change */
+        return det_ctx->alert_queue_capacity;
+    }
+    det_ctx->alert_queue = tmp_queue;
+    det_ctx->alert_queue_capacity = new_cap;
+    SCLogDebug("Alert queue size expanded: %u elements, bytes: %" PRIuMAX "",
+            det_ctx->alert_queue_capacity, (uintmax_t)(new_cap * sizeof(PacketAlert)));
+    return new_cap;
+}
+
 /** \internal
  * \retval the new capacity
  */
@@ -247,18 +263,17 @@ static uint16_t AlertQueueExpand(DetectEngineThreadCtx *det_ctx)
     if (unlikely(g_eps_is_alert_queue_fail_mode))
         return det_ctx->alert_queue_capacity;
 #endif
-    uint16_t new_cap = det_ctx->alert_queue_capacity * 2;
-    void *tmp_queue = SCRealloc(det_ctx->alert_queue, (size_t)(sizeof(PacketAlert) * new_cap));
-    if (unlikely(tmp_queue == NULL)) {
-        /* queue capacity didn't change */
+    if (det_ctx->alert_queue_capacity == UINT16_MAX) {
         return det_ctx->alert_queue_capacity;
     }
-    det_ctx->alert_queue = tmp_queue;
-    det_ctx->alert_queue_capacity = new_cap;
-    SCLogDebug("Alert queue size doubled: %u elements, bytes: %" PRIuMAX "",
-            det_ctx->alert_queue_capacity,
-            (uintmax_t)(sizeof(PacketAlert) * det_ctx->alert_queue_capacity));
-    return new_cap;
+
+    uint16_t new_cap;
+    if (det_ctx->alert_queue_capacity > (UINT16_MAX / 2)) {
+        new_cap = UINT16_MAX;
+    } else {
+        new_cap = det_ctx->alert_queue_capacity * 2;
+    }
+    return AlertQueueExpandDo(det_ctx, new_cap);
 }
 
 /** \internal